/**
 * Description:
 * Class Name:subject2_use_lock
 * Date:2022/5/19 20:26
 *
 * @author LTisme
 * @version JAVA17
 */
package 疯狂Java讲义.第16章_多线程.课后练习;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

class ParkPlace{
    public static boolean[] CommonGarage = new boolean[] {true, true, true};
}

class Car extends Thread{
    private boolean[] ShareGarage = ParkPlace.CommonGarage;
    private boolean isParked = false;
    private int parkedPoint;
    private ReentrantLock lock;
    private Condition vacancyCondition;
    private Condition isParkedCondition;

    public int getPositionIfExists(){
        for (int i = 0; i < ShareGarage.length; i++) {
            if (ShareGarage[i]){
                return i;
            }
        }
        return -1;
    }

    public Car(String name, ReentrantLock lock, Condition vacancyCondition, Condition isParkedCondition){
        super(name);
        this.lock = lock;
        this.vacancyCondition = vacancyCondition;
        this.isParkedCondition = isParkedCondition;
    }

    public void park(){
        lock.lock();
        try {
            while (getPositionIfExists() == -1){
                vacancyCondition.await();
            }
            isParked = true;
            isParkedCondition.signalAll();
            parkedPoint = getPositionIfExists();
            ShareGarage[parkedPoint] = false;
            System.out.println(Thread.currentThread().getName() + " 号车成功停车到了 " + parkedPoint + " 位置。");
        }
        catch (Exception e){
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }

    public void leave(){
        // 离开也需要加锁，把停车位看作一本书的话，离开也是进行写操作
        lock.lock();
        try {
            while (!isParked){
                isParkedCondition.await();
            }
            System.out.println(Thread.currentThread().getName() + " 号车离开了 " + parkedPoint + " 位置。");
            ShareGarage[parkedPoint] = true;
            vacancyCondition.signalAll();
            isParked = false;
        }
        catch (Exception e){
            e.printStackTrace();
        }
        finally {
            lock.unlock();
        }
    }

    @Override
    public void run() {
        try {
            park();
            Thread.sleep(500);
            leave();
        }
        catch (Exception e){
            e.printStackTrace();
        }
    }
}

public class subject2_use_lock {
    public static void main(String[] args) {
        var GarageLock = new ReentrantLock();
        var isParkedCondition = GarageLock.newCondition();
        var isVacancyCondition = GarageLock.newCondition();

        new Car("c1", GarageLock, isVacancyCondition, isParkedCondition).start();
        new Car("c2", GarageLock, isVacancyCondition, isParkedCondition).start();
        new Car("c3", GarageLock, isVacancyCondition, isParkedCondition).start();
        new Car("c4", GarageLock, isVacancyCondition, isParkedCondition).start();
        new Car("c5", GarageLock, isVacancyCondition, isParkedCondition).start();
    }
}
